'''
regexp.py

Realiza el analisis sintactico de la cadena de entrada

regexp -> binexp regexpprim
regexpprim -> '|' binexp regexpprim | e
binexp -> unexp binexpprim
binexpprim -> . unexp binexpprim | e
unexp -> caracter unop
unop -> *|+|?|e
caracter -> ALFABETO | (regexp)

'''
from arbol import *

class RegExp:

	def __init__(self, entrada = '', alfabeto = ''):
		self.entrada = entrada
		self.indice = 0
		self.alfabeto = alfabeto

	def analizar(self):
		raiz = self.regexp()
		if not self.indice == len(self.entrada):
			raise Exception('Cadena invalida, no se consumio toda la cadena')
		return raiz
	
	def regexp(self):
		#no puede derivar en vacio, llegar al fin de cadena aca es un error
		if self.indice >= len(self.entrada): 
			raise Exception('Error al consumir la entrada, cadena no valida.')
			
		if self.alfabeto.find(self.entrada[self.indice]) > -1 or self.entrada[self.indice] == '(':
			binexp_res = self.binexp()
			regexpprim_res = self.regexpprim()
			if regexpprim_res:
				regexpprim_res.add_hijo(binexp_res)
				return regexpprim_res
			else:
				return binexp_res
		else:
			raise Exception('Cadena no valida en regexp')

	def regexpprim(self):
		#nada que consumir, deriva en vacio
		if self.indice >= len(self.entrada): return
		
		if self.entrada[self.indice] == '|':
			print 'Consumido ' + self.entrada[self.indice]
			self.indice += 1
			binexp_res = self.binexp()
			regexpprim_res = self.regexpprim()
			if regexpprim_res:
				regexpprim_res.add_hijo(binexp_res)
				return Nodo('|', [regexpprim_res])
			else:
				return Nodo('|', [binexp_res])
		return None
	
	def binexp(self):
		#no puede derivar en vacio, llegar al fin de cadena aca es un error
		if self.indice >= len(self.entrada): 
			raise Exception('Error al consumir la entrada, cadena no valida.')
			
		if self.alfabeto.find(self.entrada[self.indice]) > -1 or self.entrada[self.indice] == '(':
			unexp_res = self.unexp()
			binexpprim_res = self.binexpprim()
			if binexpprim_res:
				binexpprim_res.add_hijo(unexp_res)
				return binexpprim_res
			else:
				return unexp_res
		else:
			raise Exception('Cadena no valida en binexp')

	def binexpprim(self):
		#nada que consumir, deriva en vacio
		if self.indice >= len(self.entrada): return
		
		if self.entrada[self.indice] == '.':
			print 'Consumido ' + self.entrada[self.indice]
			self.indice += 1
			unexp_res = self.unexp()
			binexpprim_res = self.binexpprim()
			if binexpprim_res:
				binexpprim_res.add_hijo(unexp_res)
				return Nodo('.', [binexpprim_res])
			else:
				return Nodo('.', [unexp_res])
			
		return None

	def unexp(self):
		#no puede derivar en vacio, llegar al fin de cadena aca es un error
		if self.indice >= len(self.entrada): 
			raise Exception('Error al consumir la entrada, cadena no valida.')
		
		if self.alfabeto.find(self.entrada[self.indice]) > -1 or self.entrada[self.indice] == '(':
			caracter = self.caracter()
			op = self.unop()
			if not op:
				return caracter
			else:
				return Nodo(op, [caracter])
		else:
			raise Exception('Cadena no valida en unexp')

	def unop(self):
		#nada que consumir, puede derivar en vacio por lo tanto solo retorna
		if len(self.entrada) <= self.indice: return
		
		if self.entrada[self.indice] in ('*', '+', '?'):
			print 'Consumido ' + self.entrada[self.indice]
			op = self.entrada[self.indice]
			self.indice += 1
			return op
		
		return None

	def caracter(self):
		#por si se llega a un fin de cadena inesperado:
		if len(self.entrada) <= self.indice:
				raise Exception('Error al consumir la entrada, cadena no valida.')
		
		if self.alfabeto.find(self.entrada[self.indice]) > -1:
			print 'Consumido ' + self.entrada[self.indice]
			caracter = self.entrada[self.indice]
			self.indice += 1
			return caracter
		elif self.entrada[self.indice] == '(':
			print 'Consumido ' + self.entrada[self.indice]
			self.indice += 1
			regexp_res = self.regexp()
			
			#por si se llega a un fin de cadena inesperado:
			if len(self.entrada) <= self.indice:
				raise Exception('Error al consumir la entrada, parentesis desbalanceado.')
				
			if self.entrada[self.indice] == ')':
				print 'Consumido ' + self.entrada[self.indice]
				self.indice += 1
			else:
				raise Exception('Caracter no valido')
			#al llegar aca se retorna el regexp
			return regexp_res
		else:
			raise Exception('Cadena no valida en caracter')

if __name__ == '__main__':
	regexp = RegExp(entrada = '(a+.b?).(b.a|b*)', alfabeto = 'ab')
	try:
		raiz = regexp.analizar()
		print 'Cadena aceptada'
		raiz.print_nodo()
	except Exception, e:
		print e

	
